"""
MDC FastAPI 中间件

自动为每个请求设置 MDC 上下文，包括请求信息、用户信息等
"""

import time
from typing import Callable

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

from app.utils.ip_utils import get_client_ip
from app.utils.mdc_context import mdc, request_mdc_context


class MDCMiddleware(BaseHTTPMiddleware):
    """MDC 中间件，自动为每个请求设置上下文"""

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        """处理请求，设置 MDC 上下文"""

        # 获取客户端 IP 信息
        client_ip = get_client_ip(request)
        ip_info = get_client_ip(request)

        # 基础请求信息
        request_info = {
            "method": request.method,
            "url": str(request.url),
            "path": request.url.path,
            "user_agent": request.headers.get("user-agent", ""),
            "client_ip": client_ip,
            "referer": request.headers.get("referer", ""),
        }

        # 使用请求 MDC 上下文
        with request_mdc_context(**request_info) as request_id:
            # 记录请求开始
            mdc.put("request_start_time", time.time())

            try:
                # 处理请求
                response = await call_next(request)

                # 记录响应信息
                mdc.put("status_code", response.status_code)
                mdc.put("response_size", response.headers.get("content-length", 0))

                return response

            except Exception as e:
                # 记录异常信息
                mdc.put("exception_type", type(e).__name__)
                mdc.put("exception_message", str(e))
                raise
            finally:
                # 计算请求处理时间
                end_time = time.time()
                start_time = mdc.get("request_start_time", end_time)
                processing_time = end_time - start_time

                mdc.put("request_end_time", end_time)
                mdc.put("processing_time_ms", round(processing_time * 1000, 2))

                # 记录请求摘要（可用于访问日志）
                self._log_request_summary(request, response if "response" in locals() else None)

    def _log_request_summary(self, request: Request, response: Response = None):
        """记录请求摘要日志"""
        import logging

        logger = logging.getLogger("mdc.middleware")

        request_id = mdc.get("request_id")
        method = mdc.get("method", "UNKNOWN")
        path = mdc.get("path", "UNKNOWN")
        status_code = mdc.get("status_code", 500)
        processing_time = mdc.get("processing_time_ms", 0)
        client_ip = mdc.get("client_ip", "UNKNOWN")

        logger.info(
            f"Request completed: {method} {path} - {status_code} "
            f"- {processing_time}ms - IP: {client_ip} - RequestID: {request_id}"
        )


class UserContextMiddleware(BaseHTTPMiddleware):
    """用户上下文中间件，从 JWT token 中提取用户信息"""

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        """处理请求，设置用户上下文"""

        # 尝试从认证头中提取用户信息
        auth_header = request.headers.get("authorization")

        if auth_header and auth_header.startswith("Bearer "):
            try:
                # 这里可以集成 JWT 解析逻辑
                # token = auth_header.replace("Bearer ", "")
                # user_info = await self._extract_user_from_token(token)

                # 示例：模拟用户信息提取
                user_info = self._extract_user_from_headers(request)
                if user_info:
                    mdc.put("user_id", user_info.get("user_id"))
                    mdc.put("username", user_info.get("username"))
                    mdc.put("user_roles", user_info.get("roles", []))

            except Exception as e:
                # 认证失败不影响请求处理，只是不设置用户上下文
                pass

        return await call_next(request)

    def _extract_user_from_headers(self, request: Request) -> dict:
        """从请求头中提取用户信息（示例实现）"""
        # 在实际项目中，这里应该解析 JWT token
        user_id = request.headers.get("x-user-id")
        username = request.headers.get("x-username")

        if user_id and username:
            return {
                "user_id": int(user_id),
                "username": username,
                "roles": (
                    request.headers.get("x-user-roles", "").split(",") if request.headers.get("x-user-roles") else []
                ),
            }

        return {}


def setup_mdc_middleware(app):
    """设置 MDC 中间件"""
    app.add_middleware(MDCMiddleware)
    app.add_middleware(UserContextMiddleware)
